# 导入必要的库
import os  # 用于文件和目录操作
import pickle  # 用于数据序列化和反序列化（存储/加载人脸特征）

import tkinter as tk  # 用于创建图形用户界面(GUI)
from tkinter import messagebox  # 用于显示消息对话框
import face_recognition  # 用于人脸识别相关操作（提取特征、比对等）


def get_button(window, text, color, command, fg='white'):
    """
    创建并返回一个自定义样式的按钮组件

    参数:
        window: 按钮所在的父窗口
        text: 按钮上显示的文本
        color: 按钮的背景颜色
        command: 按钮点击时触发的函数
        fg: 按钮文本颜色，默认白色
    返回:
        配置好的Button对象
    """
    button = tk.Button(
        window,
        text=text,
        activebackground="black",  # 按钮被点击时的背景色
        activeforeground="white",  # 按钮被点击时的文本色
        fg=fg,  # 文本颜色
        bg=color,  # 背景颜色
        command=command,  # 点击事件回调函数
        height=2,  # 按钮高度
        width=20,  # 按钮宽度
        font=('Helvetica bold', 20)  # 字体样式和大小
    )

    return button


def get_img_label(window):
    """
    创建并返回一个用于显示图像的标签组件

    参数:
        window: 标签所在的父窗口
    返回:
        配置好的Label对象（默认放置在网格布局的第0行第0列）
    """
    label = tk.Label(window)
    label.grid(row=0, column=0)  # 设置标签在网格布局中的位置
    return label


def get_text_label(window, text):
    """
    创建并返回一个用于显示文本的标签组件

    参数:
        window: 标签所在的父窗口
        text: 标签显示的文本内容
    返回:
        配置好的Label对象（带特定字体和对齐方式）
    """
    label = tk.Label(window, text=text)
    label.config(font=("sans-serif", 21), justify="left")  # 设置字体和左对齐
    return label


def get_entry_text(window):
    """
    创建并返回一个文本输入框组件

    参数:
        window: 输入框所在的父窗口
    返回:
        配置好的Text对象（用于用户输入文本）
    """
    inputtxt = tk.Text(window,
                       height=2,  # 输入框高度（行数）
                       width=15,  # 输入框宽度（字符数）
                       font=("Arial", 32)  # 输入字体样式和大小
                       )
    return inputtxt


def msg_box(title, description):
    """
    显示一个信息提示对话框

    参数:
        title: 对话框标题
        description: 对话框显示的内容
    """
    messagebox.showinfo(title, description)


def recognize(img, db_path):
    """
    识别人脸图像，与数据库中的人脸进行比对并返回结果

    参数:
        img: 待识别的人脸图像（OpenCV格式）
        db_path: 存储已注册人脸特征的数据库目录路径
    返回:
        识别结果：
            - 已注册用户的用户名（字符串）
            - 'no_persons_found'：未检测到人脸
            - 'unknown_person'：检测到人脸但未匹配到数据库中的用户
    """
    # 假设数据库中最多有一个匹配项

    # 提取待识别图像中的人脸特征编码
    embeddings_unknown = face_recognition.face_encodings(img)

    # 检查是否检测到人脸
    if len(embeddings_unknown) == 0:
        return 'no_persons_found'
    else:
        # 取第一个检测到的人脸特征（默认只处理一张人脸）
        embeddings_unknown = embeddings_unknown[0]

    # 获取数据库目录下的所有文件（按名称排序）
    db_dir = sorted(os.listdir(db_path))

    match = False  # 匹配标志，初始为False
    j = 0  # 循环索引
    # 在找到匹配项或遍历完所有文件前持续循环
    while not match and j < len(db_dir):
        # 构建数据库中当前文件的完整路径
        path_ = os.path.join(db_path, db_dir[j])

        # 打开文件并加载已保存的人脸特征编码（通过pickle序列化的）
        file = open(path_, 'rb')
        embeddings = pickle.load(file)

        # 比对未知人脸特征与数据库中的特征，返回是否匹配
        match = face_recognition.compare_faces([embeddings], embeddings_unknown)[0]
        j += 1  # 索引递增

    # 根据匹配结果返回对应信息
    if match:
        # 数据库文件名格式假设为"用户名.pickle"，[:-7]去除".pickle"后缀得到用户名
        return db_dir[j - 1][:-7]
    else:
        return 'unknown_person'
